﻿Imports System.Drawing.Drawing2D

Public Class Layout : Inherits BaseControl

	Public IntHeaders As New List(Of Header)

	Dim MustRearrange As Boolean

	Sub New()
		DoubleBuffered = True
		ResizeRedraw = True
		'VerticalScroll.Visible = True
	End Sub

	ReadOnly Property Headers(Name As String) As Header
		Get
			Return (From h In IntHeaders Where h.Name = Name).FirstOrDefault
		End Get
	End Property

	Public Overrides Sub Reset()
		MyBase.Reset()
		IntHeaders.Clear()
		Invalidate()
	End Sub

	Dim _Selected As Rectangle
	Property Selected As Rectangle
		Get
			Return _Selected
		End Get
		Set(value As Rectangle)
			If value = Selected Then Return
			Invalidate(Selected)
			If value = Rectangle.Empty Then Cursor = Cursors.Default Else Cursor = Cursors.Hand
			_Selected = value
			Invalidate(Selected)
		End Set
	End Property

	Dim _Pressed As Rectangle
	Property Pressed As Rectangle
		Get
			Return _Pressed
		End Get
		Set(value As Rectangle)
			If value = Pressed Then Return
			Invalidate(Pressed)
			If value = Rectangle.Empty Then Cursor = Cursors.Default Else Cursor = Cursors.Hand
			_Pressed = value
			Invalidate(Pressed)
		End Set
	End Property

	Protected Overrides Sub OnMouseLeave(e As System.EventArgs)
		MyBase.OnMouseLeave(e)
		Selected = Rectangle.Empty
		Pressed = Rectangle.Empty
	End Sub

	Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, keyData As System.Windows.Forms.Keys) As Boolean
		If keyData = Keys.Enter Then
			SendKeys.Send("{TAB}")
			Return True
		End If
		Select Case keyData
			Case Keys.Up : SafeScroll(-16) : Return True
			Case Keys.Down : SafeScroll(16) : Return True
			Case Keys.PageUp : SafeScroll(-Height) : Return True
			Case Keys.PageDown : SafeScroll(Height) : Return True
		End Select
		Return MyBase.ProcessCmdKey(msg, keyData)
	End Function

	Sub AddHeader(Name As String, Text As String)
		Dim Header As New Header(Me)
		Header.Name = Name
		Header.Text = Text
		IntHeaders.Add(Header)
		MustRearrange = True
		Invalidate()
	End Sub

	Sub AddRow(Header As String, Text As String)
		Headers(Header).AddRow(Text)
	End Sub

	Protected Overrides Sub OnSizeChanged(e As System.EventArgs)
		MyBase.OnSizeChanged(e)
		MustRearrange = True
		Invalidate()
	End Sub

	Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
		MyBase.OnPaint(e)
		Rearrange()
		e.Graphics.TranslateTransform(0, -VerticalScroll.Value)
		For Each Header In IntHeaders
			Header.Draw(e)
		Next
	End Sub

	Protected Overrides Function ProcessDialogKey(keyData As System.Windows.Forms.Keys) As Boolean
		Return MyBase.ProcessDialogKey(keyData)
	End Function

	Protected Overrides Function IsInputKey(keyData As System.Windows.Forms.Keys) As Boolean
		Select Case keyData
			Case Keys.Up, Keys.Down, Keys.PageUp, Keys.PageDown : Return True
		End Select
		Return MyBase.IsInputKey(keyData)
	End Function

	Sub Rearrange()
		If Not MustRearrange Then Return
		Dim y As Integer = 0
		For Each Header In IntHeaders
			Header.Rearrange(y, Width)
		Next
		AutoScrollMinSize = New Size(0, y)
		y = 0
		For Each Header In IntHeaders
			Header.Rearrange(y, ClientRectangle.Width)
		Next
		MustRearrange = False
	End Sub

	Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)
		MyBase.OnMouseMove(e)
		For Each Header In IntHeaders
			If Header.OnMouseMove(e) Then Return
		Next
		Selected = Rectangle.Empty
	End Sub

	Protected Overrides Sub OnMouseDown(e As System.Windows.Forms.MouseEventArgs)
		MyBase.OnMouseDown(e)
		If Selected = Rectangle.Empty Then Return
		Pressed = Selected
	End Sub

	Protected Overrides Sub OnMouseUp(e As System.Windows.Forms.MouseEventArgs)
		MyBase.OnMouseUp(e)
		If Not Pressed = Rectangle.Empty Then
			RaiseActionEvent(GetActiveItem)
		End If
		Pressed = Rectangle.Empty
	End Sub

	Function GetActiveItem() As String
		For Each Header In IntHeaders
			Dim Item = Header.GetActiveItem
			If Item <> "" Then Return Item
		Next
		Return ""
	End Function

	Class Header

		Public Name As String
		Public Text As String
		Public Layout As Layout

		Dim HeaderRect As Rectangle
		Dim Buttons As New List(Of Button)
		Dim Rows As New List(Of Row)

		Sub New(Layout As Layout)
			Me.Layout = Layout
		End Sub

		Sub Rearrange(ByRef y As Integer, w As Integer)
			HeaderRect = New Rectangle(0, y, w, 32)
			Dim x = HeaderRect.Right
			For Each Button In Buttons
				Button.Rearrange(x, y, HeaderRect.Height)
			Next
			y += HeaderRect.Height
			y += 4
			For Each Row In Rows
				Row.Rearrange(y, w)
			Next
			y += 8
		End Sub

		Sub Draw(e As PaintEventArgs)
			Dim R = HeaderRect
			e.Graphics.FillRectangle(Themes.Current.FormColor.Brush, R)
			For y = 1 To 4
				e.Graphics.DrawLine(Color.Black.Opacity(64 / y ^ 1.4).Pen, R.Left, R.Bottom + y - 1, R.Right, R.Bottom + y - 1)
			Next
			R.Inflate(-4, 0)
			DrawStringLighted(e.Graphics, Text, New Font(Themes.Current.Font.Name, Themes.Current.Font.Size + 2), Color.DarkRed, R, StrFormat("lm"), 0, 1)
			For Each Button In Buttons
				Button.Draw(e)
			Next
			For Each Row In Rows
				Row.Draw(e)
			Next
		End Sub

		Sub AddButton(Name As String, Text As String)
			Dim Button As New Button(Me)
			Button.Name = Name
			Button.Text = Text
			Buttons.Add(Button)
		End Sub

		Sub AddRow(Text As Object)
			Dim Row As New Row(Me)
			Row.Text = Text
			Rows.Add(Row)
		End Sub

		Function OnMouseMove(e As MouseEventArgs) As Boolean
			For Each Button In Buttons
				If Button.OnMouseMove(e) Then Return True
			Next
		End Function

		Function GetActiveItem() As Object
			For Each Button In Buttons
				If Button.Rect = Layout.Pressed Then Return Button.Name
			Next
			Return ""
		End Function

	End Class

	Class Button
		Public Name As String
		Public Text As String
		Public Header As Header
		Public Rect As Rectangle

		Sub New(Header As Header)
			Me.Header = Header
		End Sub

		Sub Rearrange(ByRef x As Integer, y As Integer, h As Integer)
			Rect = New Rectangle(0, 0, 72, 24)
			x -= 4 + Rect.Width
			Rect.Offset(x, y + (h - Rect.Height) / 2)
		End Sub

		Sub Draw(e As PaintEventArgs)
			Renderer.PaintButton(e.Graphics, Rect, Me, Header.Layout.Pressed = Rect, Header.Layout.Selected = Rect, False, True, False)
			DrawText2(e.Graphics, Text, Header.Layout.Font, Color.Black, Rect, StrFormat("mc"))
		End Sub

		Function OnMouseMove(e As MouseEventArgs) As Boolean
			If Not Rect.Contains(e.Location) Then Return False
			Header.Layout.Selected = Rect
			Return True
		End Function

	End Class

	Class Row
		Public Name As String
		Public Text As String
		Public Header As Header
		Public Rect As Rectangle

		Sub New(Header As Header)
			Me.Header = Header
		End Sub

		Sub Rearrange(ByRef y As Integer, w As Integer)
			Rect = New Rectangle(0, y, w, 26)
			y += Rect.Height
		End Sub

		Sub Draw(e As PaintEventArgs)
			Dim Value = Me.Text
			Dim G = e.Graphics
			Dim R = Rect
			Select Case Mid(Value, 1, 3)
				Case "[x]", "[!]", "[/]", "[?]", "[-]", "[i]", "[+]"
					DrawCellIcon(G, R, Mid(Value, 2, 1))
					Value = Mid(Value, 4)
					R.Offset(R.Height, 0)
					R.Width -= R.Height
			End Select
			DrawText2(G, Value, Header.Layout.Font, Color.Black, R, StrFormat("lm"))
		End Sub

		Sub DrawCellIcon(ByVal G As Graphics, ByVal R As Rectangle, ByVal Icon As String)
			G.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
			G.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
			G.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
			R.Width = R.Height
			R.Inflate(-5, -5)
			Dim Clr As Color = Color.Black
			G.InterpolationMode = InterpolationMode.HighQualityBilinear
			Select Case Icon
				Case "x" : R.Inflate(-2, -2) : G.DrawImage(My.Resources.ierror, R) : Return
				Case "!" : G.DrawImage(My.Resources.warning, R) : Return
				Case "/" : G.DrawImage(My.Resources.check, R) : Return
				Case "i" : G.DrawImage(My.Resources.Info, R) : Return
				Case "-" : G.DrawImage(My.Resources.norapplicable, R) : Return
			End Select
			Select Case Icon
				Case "-" : Clr = Color.Gray
				Case "+" : Clr = Color.Blue
			End Select
			G.FillEllipse(New SolidBrush(Color.FromArgb(96, Color.Black)), R)
			R.Offset(-1, -1)
			G.FillEllipse(New SolidBrush(Clr), R)
			G.FillEllipse(LGBv(R, Color.Transparent, Color.FromArgb(128, Color.Black)), R)
			R.Inflate(-1, -1)
			Dim Pen As New Pen(Color.White, 2)
			Pen.StartCap = Drawing2D.LineCap.Round
			Pen.EndCap = Drawing2D.LineCap.Round
			R.Inflate(-4, -4)
			Dim Fmt As StringFormat = Centered
			Select Case Icon
				Case "-" : G.DrawLine(Pen, R.Left, CInt(R.Top + R.Height / 2), R.Right, CInt(R.Top + R.Height / 2))
				Case "+" : G.DrawLine(Pen, R.Left, CInt(R.Top + R.Height / 2), R.Right, CInt(R.Top + R.Height / 2)) : G.DrawLine(Pen, CInt(R.Left + R.Width / 2), R.Top, CInt(R.Left + R.Width / 2), R.Bottom)
			End Select
		End Sub

	End Class

	Private Sub SafeScroll(v As Integer)
		v -= AutoScrollPosition.Y
		If v < 0 Then v = 0
		If v > AutoScrollMinSize.Height Then v = AutoScrollMinSize.Height
		AutoScrollPosition = New Point(0, v)
	End Sub

End Class
